#include"udpServer.hpp"
#include"userManager.hpp"
#include<memory>
#include<unordered_map>
#include<fstream>

//Linux这边做服务器，window那边做客户端【实现聊天室功能】

//走到这里就是外部调用错误，没有传应该传的参数进来, 这里就提示一下
static void Usage(string proc)
{
    cout << "Usage: \n" << proc << "local_port\n";
}

UserManager usermanager;

// 实现简易聊天室的业务逻辑
void routeMessage(int sockfd, string clientip, uint16_t clientport, string message)
{
    // 先判断客户端发来的消息是否是上线和下线
    if(message == "online")
    {
        usermanager.addUser(clientip, clientport, sockfd);

        struct sockaddr_in client;
        bzero(&client, sizeof(client));
        client.sin_family = AF_INET;
        client.sin_addr.s_addr = inet_addr(clientip.c_str());
        client.sin_port = htons(clientport);

        string response = "online Successfully, welcome to join the chat room";
        sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr*)&client, sizeof(client));

        return;
    }
    if(message == "offline")
    {
        usermanager.delUser(clientip, clientport);

        struct sockaddr_in client;
        bzero(&client, sizeof(client));
        client.sin_family = AF_INET;
        client.sin_addr.s_addr = inet_addr(clientip.c_str());
        client.sin_port = htons(clientport);

        string response = " looking forward to your next arrival";
        sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr*)&client, sizeof(client));
        
        return;
    }
    
    // 用户想要加入群聊看到消息或者发消息，必须是在线状态
    if(usermanager.isOnline(clientip, clientport))
    {
        // 给在群聊的所有用户都发消息
        usermanager.boardcast(sockfd, message, clientip, clientport);
    }
    else
    {
        // 如果不在线，就单独给该用户说明一下
        struct sockaddr_in client;
        bzero(&client, sizeof(client));
        client.sin_family = AF_INET;
        client.sin_addr.s_addr = inet_addr(clientip.c_str());
        client.sin_port = htons(clientport);

        string response = "You are offline, please enter online";
        sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr*)&client, sizeof(client));

    }
}


// 在调用这个进程的时候要传port进来【也可以显式传ip，然后给服务器bind，但是不推荐这样做】
// ./udpServer port
int main(int argc, char* argv[])
{
    if(argc != 2) //必须得是2个元素，进程名，port。【这是命令行参数的知识，忘了就复习】
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    // 将argv中char*类型的port记载下来
    uint16_t port = atoi(argv[1]); //必须转成int类型，因为argv里面全是char*类型的元素
    
    //创建服务器对象
    std::unique_ptr<udpServer> usvr(new udpServer(routeMessage, port));  // 实现简易聊天群的业务逻辑

    usvr->initServer(); //初始化服务器
    usvr->start(); //启动服务器
    
    return 0;
}